﻿// ------------------------------------------------------------------
// FileName	：	CodeNameSelect.js
// Remark	：	代码选择
// ------------------------------------------------------------------
// VERSION		AUTHOR		DATE			CONTENT
// 1.0			席吉波	    2010-05-21	    创建
// 修改日志
// 1 修改人 席吉波，修改日期 2011-01-12
//   修改内容：当控件为ReadOnly时，隐藏Textbox，并用span来显示数据
// 2 修改人 席吉波，修改日期 2011-05-24
//   修改内容：新增OnSeletedComplete属性，此属性为客户端需要执行的方法
//             当此属性不为空时，会调用此方法，并传入一个Json参数
//             参数格式为：{Code:'',Name:''},使用者需先反序列化该参数
//             然后您就可以为所欲为了 
// ------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Web.Script.Serialization;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using AjaxControlToolkit;
//[assembly: WebResource("Kevin.Controls.Common.public.js", "text/javascript")]
[assembly: WebResource("Kevin.Controls.CodeNameSelect.CodeNameSelect.js", "text/javascript")]
[assembly: WebResource("Kevin.Controls.Dialog.css", "text/css", PerformSubstitution = true)]
[assembly: WebResource("Kevin.Controls.AutoCompletion.css", "text/css", PerformSubstitution = true)]

namespace Kevin.Controls
{
    /// <summary>
    /// 代码选择控件，功能目前稳定
    /// </summary>
    [RequiredScript(typeof(ModalPopupExtender))]    
    [ClientScriptResource("Kevin.Controls.CodeNameSelect", "Kevin.Controls.CodeNameSelect.CodeNameSelect.js")]
    //[ClientScriptResource("Kevin.Controls.Common", "Kevin.Controls.Common.public.js")]
    [RequiredScript(typeof(PopupControlExtender))]
    [RequiredScript(typeof(AnimationExtender))]
    [ClientCssResource("Kevin.Controls.Dialog.css")]
    [ClientCssResource("Kevin.Controls.AutoCompletion.css")]
    public class CodeNameSelect : ScriptControlBase
    {
        /// <summary>
        /// 构造函数，后面的继承很重要
        /// </summary>
        public CodeNameSelect()
            : base(true, HtmlTextWriterTag.Div)
        { }

        #region  [ Methodes ]

        /// <summary>
        /// 本想在运行时阶段给加上必录校验，后来一直没有做成，在DataBind控件中对此玩意有一个校验，但是还不完整
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPreRender(EventArgs e)
        {
            if (!DesignMode)
            {
                InitialiseControls();

                CreateTableItems();

                this.CallbackID = UniqueID;

                Page.ClientScript.GetCallbackEventReference(this, "", "", "");
                //ScriptObjectBuilder.RegisterCssReferences(this);
                if (this.Required && !string.IsNullOrEmpty(this.RequiredErrorMessage))
                {
                    RequiredFieldValidator valid = new RequiredFieldValidator();
                    valid.ID = this.CallbackID + "RequiredFieldValidator";
                    valid.ErrorMessage = this.RequiredErrorMessage;
                    valid.ControlToValidate = this.txtCode.ID;
                    valid.Display = ValidatorDisplay.None;
                    this.Controls.Add(valid);
                }
            }

            base.OnPreRender(e);

        }
        /// <summary>
        /// Render 这没啥好说的，在设计时会显示一个文本框和一个放大镜
        /// </summary>
        /// <param name="writer"></param>
        protected override void Render(HtmlTextWriter writer)
        {

            if (DesignMode)
            {
                string strHtml = "";
                strHtml += "<input type='text' class='" + this.TextBoxCSS + "' /><img src='" + Page.ClientScript.GetWebResourceUrl(this.GetType(), "Kevin.Controls.BTN_find.jpg") + "'></img>";

                writer.Write(strHtml);
            }
            else
            {
                base.Render(writer);
            }
        }
        /// <summary>
        /// 获取客户端状态
        /// </summary>
        /// <param name="clientState"></param>
        protected override void LoadClientState(string clientState)
        {

            if (!this.MutiSelecte)
            {
                CodeNameItem item = new JavaScriptSerializer().Deserialize<List<CodeNameItem>>(clientState)[0];
                this.Value = item.Code;
                this._Text = item.Name;

                if (!string.IsNullOrEmpty(item.Code))
                    SetPropertyValue<string>("Text", item.Name + "(" + item.Code + ")");
                else
                    SetPropertyValue<string>("Text", "");

                SetPropertyValue<string>("Name", item.Name);
            }
            else
            {
                List<CodeNameItem> items = new JavaScriptSerializer().Deserialize<List<CodeNameItem>>(clientState);
                foreach (CodeNameItem item in items)
                {
                    this.Value = this.Value + item.Code + ";";
                }
                this.Value = this.Value.Substring(0, this.Value.Length - 1);
            }

        }

        /// <summary>
        /// 保存客户端状态，如果您对Value赋值为： 名称(代码)
        /// 则此处会拆解并序列化该值
        /// </summary>
        /// <returns></returns>
        protected override string SaveClientState()
        {
            //return base.SaveClientState();
            //return this.Value;
            string strCode = "";
            string strName = "";

            /*
            else if(this.Value.Length>0)
            {
                //为提高效率，特在此处调用webservice再POST给客户端浏览器
                string servicePath = "http://" + Page.Request.Url.Authority + ResolveUrl(this.ServicePath);
                string strResult = "";
                //在常熟的时候经常出现调用service失败,暂时隐藏这一优化功能
                //strResult=(string)DynamicInvokWebService.InvokeWebService(servicePath, this.ServiceMethod, new object[] { Value, 1, 1 });
                if (strResult.Contains("Code"))
                {
                    strName = new JavaScriptSerializer().Deserialize<IList<CodeNameItem>>(strResult)[0].Name;
                    SetPropertyValue<string>("Name", strName);
                    //this.txtCode.Text = this.Name + "(" + this.Value + ")";
                    this.Value = this.Name + "(" + this.Value + ")";
                }
            }
            */
            List<CodeNameItem> items = new List<CodeNameItem>();
            if (this.MutiSelecte)
            {
                //多项选择
                string[] codeArray = this.Value.Split(';');
                foreach (string code in codeArray) 
                {
                    if (code.EndsWith(")"))
                    {
                        items.Add(new CodeNameItem() { Code = code.Substring(code.LastIndexOf("(")+1, code.LastIndexOf(")") - code.LastIndexOf("(")-1), Name = code.Substring(0, code.LastIndexOf("(")) });
                    }
                    else
                    {
                        items.Add(new CodeNameItem() { Code = code, Name = "" });
                    }
                }
            }
            else
            {   //单项选择
                if (this.Value.EndsWith(")"))
                {
                    this.txtCode.Text = this.Value;
                }
                items.Add(new CodeNameItem() { Code = this.Value, Name = this.Name });
            }
            return new JavaScriptSerializer().Serialize(items);
        }
        /// <summary>
        /// 初始化代码选择框及放大镜
        /// </summary>
        private void InitialiseControls()
        {

            txtCode = new TextBox();

            txtCode.ID = "txtCode";

            if (this.TextBoxCSS != null)
                this.txtCode.CssClass = this.TextBoxCSS;

            if (!this.MutiSelecte)
            {
                this.txtCode.Width = this.TextBoxWidth;
            }

            this.Controls.Add(txtCode);
            
            Image image = new Image();
            image.ID = "imgSelect";
            image.ImageUrl = this.ImgButtonURL;
            image.Width = 14;
            image.Height = 14;
            image.Style.Add("display", "inline");

            Label span = new Label();
            span.ID = "Span";
            this.Controls.Add(span);

            if (this.ReadOnly)
            {
                txtCode.Attributes.Add("display", "none");
                image.Style.Add("display", "none");
            }
            else
            {

                txtCode.Attributes.Remove("readonly");
            }

            image.Style.Add(HtmlTextWriterStyle.Cursor, "pointer");
            image.Attributes.Add("align", "absmiddle");
            this.Controls.Add(image);

            //table.Rows[0].Cells[0].Controls.Add(image);

            PopupDiv = new HtmlGenericControl();
            PopupDiv.ID = "PopupDiv";
            PopupDiv.Style.Add(HtmlTextWriterStyle.Display, "none");
            this.Controls.Add(PopupDiv);
        }

        /// <summary>
        /// 垃圾方法，当时脑子进水时写的
        /// </summary>
        private void CreateTableItems()
        {
            //TableItems.Rows.Clear();
        }

        #endregion

        #region [Properties]

        HtmlGenericControl PopupDiv;

        HtmlTable TableItems;

        TextBox txtCode;
        [ExtenderControlProperty]
        [Browsable(false)]
        public string CallbackID
        {
            [DebuggerStepThrough]
            get { return GetPropertyValue("CallbackID", UniqueID); }
            [DebuggerStepThrough]
            set { SetPropertyValue("CallbackID", value); }
        }
        /// <summary>
        /// 暂时不用
        /// </summary>
        public bool Required
        {
            get { return GetPropertyValue<bool>("RequiredValidator", false); }
            set { SetPropertyValue<bool>("RequiredValidator", value); }
        }

        [ExtenderControlProperty]
        [ClientPropertyName("useContextKey")]
        [DefaultValue(false)]
        public bool UseContextKey
        {
            get { return GetPropertyValue<bool>("UseContextKey", false); }
            set { SetPropertyValue<bool>("UseContextKey", value); }
        }

        /// <summary>
        /// The web service method to be called.
        /// </summary>
        [DefaultValue("")]
        [RequiredProperty]
        [ExtenderControlProperty]
        [ClientPropertyName("serviceMethod")]
        public virtual string ServiceMethod
        {
            get { return GetPropertyValue("ServiceMethod", String.Empty); }
            set { SetPropertyValue("ServiceMethod", value); }
        }

        /// <summary>
        /// The path to the web service that the extender will pull the 
        /// word\sentence completions from. If this is not provided, the 
        /// service method should be a page method. 
        /// </summary>
        [UrlProperty]
        [ExtenderControlProperty]
        [TypeConverter(typeof(ServicePathConverter))]
        [ClientPropertyName("servicePath")]
        [Description("webService路径")]
        public virtual string ServicePath
        {
            get { return GetPropertyValue("ServicePath", String.Empty); }
            set { SetPropertyValue("ServicePath", value); }
        }

        /// <summary>
        /// 代码选择弹出框的标题
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("CodeNameWindowForm_TitleText")]
        [Description("弹出窗口-Title")]
        public virtual string DialogTitle
        {
            get { return GetPropertyValue("CodeNameWindowForm_TitleText", "神州数码（苏州）国信有限公司-代码选择窗口"); }
            set { SetPropertyValue("CodeNameWindowForm_TitleText", value); }
        }

        /// <summary>
        /// User/page specific context provided to an optional overload of the
        /// web method described by ServiceMethod/ServicePath.  If the context
        /// key is used, it should have the same signature with an additional
        /// parameter named contextKey of type string.
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("contextKey")]
        [DefaultValue(null)]
        public string ContextKey
        {
            get { return GetPropertyValue<string>("ContextKey", null); }
            set
            {
                SetPropertyValue<string>("ContextKey", value);
                UseContextKey = true;
            }
        }
        /// <summary>
        /// 代码值
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("Value")]
        [DefaultValue("")]
        [Description("代码值")]
        public string Value
        {
            get
            {
                return GetPropertyValue<string>("Value", "");
            }
            set
            {
                if (value != null)
                {
                    SetPropertyValue<string>("Value", value);
                    this._Text = value;
                }
                else
                {
                    //赋空值时 Value Name都应该清空
                    SetPropertyValue<string>("Name", "");
                    SetPropertyValue<string>("Value", "");
                }
            }
        }

        /// <summary>
        /// 是否允许用户自定义文本信息，默认false
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("EnabledUserChangeText")]
        [DefaultValue(false)]
        public bool EnabledUserChangeText
        {
            get { return GetPropertyValue<bool>("EnabledUserChangeText", false); }
            set
            {
                SetPropertyValue<bool>("EnabledUserChangeText", value);
            }
        }

        /// <summary>
        /// 控件联动时,控件值的来源所依赖的父控件的客户端ID
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("ParentControlClientID")]
        [DefaultValue("")]
        public string ParentControlClientID {
            get
            {
                return  GetPropertyValue<string>("ParentControlClientID", "");

            }
            set
            {
                SetPropertyValue<string>("ParentControlClientID", value);
            }
        }

        /// <summary>
        /// 控件联动时，控件值所依赖的父控件的值 的客户端取值方法名，如果不指定此方法名，则当HTML基础控件处理，如果是自己封装的或者第三方的的控件请酌情处理
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("ParentControlClientValueMethod")]
        [DefaultValue("")]
        public string ParentControlClientValueMethod
        {
            get
            {
                return GetPropertyValue<string>("ParentControlClientValueMethod", "");

            }
            set
            {
                SetPropertyValue<string>("ParentControlClientValueMethod", value);
            }
        }

        /// <summary>
        /// 暂时不用
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("RequiredErrorMessage")]
        [DefaultValue("")]
        public string RequiredErrorMessage
        {
            get { return GetPropertyValue<string>("RequiredErrorMessage", ""); }
            set
            {
                SetPropertyValue<string>("RequiredErrorMessage", value);
            }
        }

        private string _Text = "";
        /// <summary>
        /// 返回名称及代码
        /// </summary>
        [Description("返回如下类型 代码名称(代码值)")]
        //[ExtenderControlProperty] IE8下会有问题
        public string Text
        {
            get { return GetPropertyValue<string>("Text", ""); }

        }
        /// <summary>
        /// 是否开启自动完成功能，默认开启
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("autoComplete")]
        [Description("是否开启Autocomplete功能,默认开启")]
        public bool AutoComplete
        {
            get { return GetPropertyValue<Boolean>("autoComplete", true); }
            set { SetPropertyValue<Boolean>("autoComplete", value); }
        }
        /// <summary>
        /// 触发自动完成功能的最少字符数
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("minimumPrefixLength")]
        [Description("AutoComplete 客户录入最小长度,默认为 2")]
        public int MinimumPrefixLength
        {
            get { return GetPropertyValue<int>("minimumPrefixLength", 2); }
            set { SetPropertyValue<int>("minimumPrefixLength", value); }
        }
        /// <summary>
        /// 自动完成功能调用服务的最短时间
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("completionInterval")]
        [Description("AutoComplete 调用webservice的最短时间，默认200毫秒")]
        public virtual int CompletionInterval
        {
            get { return GetPropertyValue("CompletionInterval", 200); }
            set { SetPropertyValue("CompletionInterval", value); }
        }

        /// <summary>
        /// 自动完成列表显示的记录数，默认值为10
        /// </summary>
        [DefaultValue(10)]
        [ExtenderControlProperty]
        [ClientPropertyName("completionSetCount")]
        public virtual int CompletionSetCount
        {
            get { return GetPropertyValue("CompletionSetCount", 10); }
            set { SetPropertyValue("CompletionSetCount", value); }
        }

        /// <summary>
        /// 返回名称
        /// </summary>
        [Description("只返回 名称")]
        public string Name
        {
            get { return GetPropertyValue<string>("Name", ""); }
        }
        /// <summary>
        /// 代码选择只读属性，默认值为false
        /// 当值为true时，文本框和放大镜将隐藏
        /// 且以一个span来显示数据
        /// </summary>
        [DefaultValue(false)]
        [ExtenderControlProperty]
        [ClientPropertyName("ReadOnly")]
        public bool ReadOnly
        {
            get { return GetPropertyValue("ReadOnly", false); }
            set { SetPropertyValue("ReadOnly", value); }
        }

        /// <summary>
        /// 文本框的宽度 
        /// </summary>
        [DefaultValue(120)]
        [ExtenderControlProperty]
        [ClientPropertyName("ElementWidth")]
        public Unit TextBoxWidth
        {
            get { return GetPropertyValue<Unit>("TextBoxWidth", 120); }
            set { SetPropertyValue<Unit>("TextBoxWidth", (Unit)value); }
        }
        /// <summary>
        /// 文本框的CSS样式
        /// </summary>
        public string TextBoxCSS
        {
            get { return GetPropertyValue("TextBoxCSS", "NormalInputText"); }
            set { SetPropertyValue("TextBoxCSS", value); }
        }

        /// <summary>
        /// Css Class that will be used to style the completion list flyout.
        /// </summary>
        [DefaultValue("")]
        [ExtenderControlProperty]
        [ClientPropertyName("completionListCssClass")]
        public string CompletionListCssClass
        {
            get { return GetPropertyValue("CompletionListCssClass", "completionListElement"); }
            set { SetPropertyValue("CompletionListCssClass", value); }
        }

        /// <summary>
        /// Css Class that will be used to style an item in the autocomplete list.
        /// </summary>
        [DefaultValue("")]
        [ExtenderControlProperty]
        [ClientPropertyName("completionListItemCssClass")]
        public string CompletionListItemCssClass
        {
            get { return GetPropertyValue("CompletionListItemCssClass", "listItem"); }
            set { SetPropertyValue("CompletionListItemCssClass", value); }
        }

        /// <summary>
        /// Css Class that will be used to style a highlighted item in the autocomplete list.
        /// </summary>
        [DefaultValue("")]
        [ExtenderControlProperty]
        [ClientPropertyName("highlightedItemCssClass")]
        public string CompletionListHighlightedItemCssClass
        {
            get { return GetPropertyValue("CompletionListHighlightedItemCssClass", "highlightedListItem"); }
            set { SetPropertyValue("CompletionListHighlightedItemCssClass", value); }
        }

        /// <summary>
        /// 弹出窗体的 CSS 样式
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("DialogCssClass")]
        [Description("弹出窗体的 CSS 样式")]
        public string DialogCssClass
        {
            get { return GetPropertyValue("DialogCssClass", "dialog"); }
            set { SetPropertyValue("DialogCssClass", value); }
        }
        /// <summary>
        /// 弹出窗体中数据列表的 CSS 样式
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("DialogDataListCssClass")]
        [Description("弹出窗体中数据列表的 CSS 样式")]
        public string DialogDataListCssClass
        {
            get { return GetPropertyValue("DialogDataListCssClass", "List"); }
            set { SetPropertyValue("DialogDataListCssClass", value); }
        }
        /// <summary>
        /// 自定义放大镜按钮图片URL
        /// </summary>
        [Description("放大镜按钮图片URL")]
        public string ImgButtonURL
        {
            get { return GetPropertyValue("ImgButtonURL", Page.ClientScript.GetWebResourceUrl(this.GetType(), "Kevin.Controls.BTN_find.jpg")); }
            set { SetPropertyValue("ImgButtonURL", value); }
        }
        /// <summary>
        /// 自动完成提示列表隐藏时动画参数，暂不使用
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("onHide")]
        public string ComletionListOnHidenJSON
        {
            get { return GetPropertyValue("onHide", ""); }
            set { SetPropertyValue("onHide", value); }
        }

        /// <summary>
        /// 自动完成提示列表显示时动画参数，暂不使用
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("onShow")]
        public string ComletionListOnShowJSON
        {
            get
            {
                return GetPropertyValue("onShow", "");
            }
            set { SetPropertyValue("onShow", value); }
        }
        /// <summary>
        /// 代码选择框隐藏时动画参数，暂不使用
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("onWindowHide")]
        public string CodeNameWindowOnHidenJSON
        {
            get { return GetPropertyValue("onWindowHide", ""); }
            set { SetPropertyValue("onWindowHide", value); }
        }

        /// <summary>
        /// 代码选择框展示时动画参数，暂不使用
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("onWindowShow")]
        public string CodeNameWindowOnShowJSON
        {
            get
            {
                return GetPropertyValue("onWindowShow", "");
            }
            set { SetPropertyValue("onWindowShow", value); }
        }

        /// <summary>
        /// Name放置控件的客户端ID
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("nameControlID")]
        public string NameControlID
        {
            get
            {
                return GetPropertyValue("nameControlID", "");
            }
            set { SetPropertyValue("nameControlID", value); }
        }
        /// <summary>
        /// 选择完成后出发的客户端方法,将会传入一个JSON对象参数
        /// {Code:'',Name:''}
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("onSelectedComplete")]
        public string OnSelectedComplete
        {
            get { return GetPropertyValue("onSelectedComplete", ""); }
            set { SetPropertyValue("onSelectedComplete", value); }
        }

        /// <summary>
        /// 多项选择，当此属性设置为true时，传入的value需以“;”分割的字符串，
        /// 您获得的value也是以“;”分割的一个字符串
        /// </summary>
        [ExtenderControlProperty]
        [ClientPropertyName("mutiSelecte")]
        public bool MutiSelecte
        {
            get { return GetPropertyValue("mutiSelecte", false); }
            set { SetPropertyValue("mutiSelecte", value); }
        }
        #endregion

        #region Helper methods
        /// <summary>
        /// Retrieves the property value from the ViewState
        /// </summary>
        /// <typeparam name="V">Type of value</typeparam>
        /// <param name="propertyName">Property to retrieve</param>
        /// <param name="nullValue">value to be used in case it's not initialised.</param>
        /// <returns></returns>
        [DebuggerStepThrough]
        protected V GetPropertyValue<V>(string propertyName, V nullValue)
        {
            if (ViewState[propertyName] == null)
            {
                return nullValue;
            }
            return (V)ViewState[propertyName];
        }


        /// <summary>
        /// Save the property value in the ViewState
        /// </summary>
        /// <typeparam name="V">Property type</typeparam>
        /// <param name="propertyName">Property name</param>
        /// <param name="value">Value</param>
        [DebuggerStepThrough]
        protected void SetPropertyValue<V>(string propertyName, V value)
        {
            ViewState[propertyName] = value;
        }
        protected Animation GetAnimation(ref Animation animation, string name)
        {
            if (animation == null)
                animation = Animation.Deserialize(GetPropertyValue(name, ""));
            return animation;
        }
        protected void SetAnimation(ref Animation animation, string name, Animation value)
        {
            animation = value;
            SetPropertyValue(name,
                animation != null ? animation.ToString() : string.Empty);
        }
        protected void ResolveControlIDs(Animation animation)
        {
            if (animation == null)
            {
                return;
            }

            // See if the animation had a target
            string id;
            if (animation.Properties.TryGetValue("AnimationTarget", out id) && !string.IsNullOrEmpty(id))
            {
                // Try to find a control with the target's id by walking up the NamingContainer tree
                Control control = null;
                Control container = NamingContainer;
                while ((container != null) && ((control = container.FindControl(id)) == null))
                {
                    container = container.Parent;
                }

                // If we found a control
                if (control != null)
                {
                    // Map the server ID to the client ID
                    animation.Properties["AnimationTarget"] = control.ClientID;
                }
            }

            // Resolve any server control IDs in the animation's children
            foreach (Animation child in animation.Children)
            {
                ResolveControlIDs(child);
            }
        }
        private string ExecuteServerEvent(string argument)
        {
            string eventArgs = argument.Substring(argument.IndexOf(";") + 1);

            return "";
        }
        #endregion
    }
}
